//
//  CLRunLoopInputSource.m
//  RunloopTest
//
//  Created by Charles on 2016/10/7.
//  Copyright © 2016年 Charles. All rights reserved.
//

#import "CLRunLoopInputSource.h"
#import "AppDelegate.h"

@interface CLRunLoopInputSource () {
    CFRunLoopSourceRef _runLoopSource;
    NSMutableArray * _commands;
    NSString * _printString;
}

@end

/*Run Loop Source Context的三个回调方法*/

//当把当前的Run Loop Source 添加到Run Loop中时,会回调这个方法.主线程管理该Input Source,所以使用performSelectorOnMainThread通知主线程.主线程和当前线程的通信使用CLRunLoopContext对象来完成.

void runLoopSourceScheduleRoutine(void *info,CFRunLoopRef runLoopRef,CFStringRef mode){
    CLRunLoopInputSource * runLoopInputSource = (__bridge CLRunLoopInputSource *)info;
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
    CLRunLoopContext *runLoopContext = [[CLRunLoopContext alloc]initWithSource:runLoopInputSource runLoop:runLoopRef];
    [appDelegate performSelectorOnMainThread:@selector(registerSource:) withObject:runLoopContext waitUntilDone:NO];
}

void runLoopSourcePerformRoutine(void *info){
    CLRunLoopInputSource *runLoopInputSource = (__bridge CLRunLoopInputSource *)(info);
    [runLoopInputSource inputSourceFired];
}

void runLoopSourceCancelRoutine (void *info,CFRunLoopRef runLoopRef,CFStringRef mode){
    CLRunLoopInputSource *runLoopInputSource = (__bridge CLRunLoopInputSource *)(info);
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
    CLRunLoopContext *runLoopContext = [[CLRunLoopContext alloc]initWithSource:runLoopInputSource runLoop:runLoopRef];
    [appDelegate performSelectorOnMainThread:@selector(removeSource:) withObject:runLoopContext waitUntilDone:YES];
}

@implementation CLRunLoopInputSource

- (instancetype)init{
    if (self = [super init]) {
        CFRunLoopSourceContext context = {0,(__bridge void *)(self),NULL, NULL, NULL, NULL, NULL,&runLoopSourceScheduleRoutine,&runLoopSourceCancelRoutine,&runLoopSourcePerformRoutine};
        _runLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
        _commands = [NSMutableArray array];
    }
    return self;
}

- (void)addToCurrentRunLoop{
    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
    CFRunLoopAddSource(runLoop, _runLoopSource, kCFRunLoopDefaultMode);
}

- (void)invalidate{
    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
    CFRunLoopRemoveSource(runLoop, _runLoopSource, kCFRunLoopDefaultMode);
}

- (void)inputSourceFired{
    if (_printString) {
        if ([self.delegate respondsToSelector:@selector(activeInputSourceForPrintStringEvent:)]) {
            [self.delegate activeInputSourceForPrintStringEvent:_printString];
        }
    }
    NSLog(@"Exit inputSourceFired");
}

- (void)addCommand:(NSInteger)command data:(NSData *)data{
    
}

- (void)addPrintCommandWithString:(NSString *)string{
    NSLog(@"Current Thread: %@",[NSThread currentThread]);
    _printString = string;
}

- (void)fireAllCommandsOnRunLoop:(CFRunLoopRef)runLoop{
    NSLog(@"Current Thread: %@",[NSThread currentThread]);
    CFRunLoopSourceSignal(_runLoopSource);
    CFRunLoopWakeUp(runLoop);
}

@end

@implementation CLRunLoopContext

- (instancetype)initWithSource:(CLRunLoopInputSource *)runLoopInputSource runLoop:(CFRunLoopRef)runLoop{
    if (self = [super init]) {
        _runLoopInputSource = runLoopInputSource;
        _runLoop = runLoop;
    }
    return self;
}

@end
